/*
 *    This file is part of SSHTunneler.
 *
 *    Copyright 2009 Jean-Sebastien Gelinas <calestar@gmail.com>
 *
 *    SSHTunneler is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    SSHTunneler is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with SSHTunneler.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package sshtunneler.client.ssh;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;

import sshtunneler.library.Server;
import sshtunneler.library.Tunnel;

import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class SSHConnection {

	private Server server;
	private SSHUserData data;
	Session session;
	private List<Tunnel> established_tunnels = new ArrayList<Tunnel>();

	public SSHConnection(Server server, SSHUserData data, Session session) {
		this.server = server;
		this.data = data;
		this.session = session;
	}

	public boolean establishAllTunnels() {
		boolean allOk = true;

		for (Tunnel tunnel : this.server.getTunnels()) {
			allOk &= this.establishTunnel(tunnel);
		}
		return allOk;
	}

	public boolean tunnel_is_established(Tunnel tunnel) {
		if (this.established_tunnels.contains(tunnel)) {
			return true;
		} else {
			return false;
		}
	}

	public boolean destroyTunnel(Tunnel tunnel) {
		if (!this.tunnel_is_established(tunnel)) {
			return false;
		}

		int tunnelLocalPort = tunnel.getLocalPort();
		try {
			this.session.delPortForwardingL(tunnelLocalPort);
			this.established_tunnels.remove(tunnel);
			return true;
		} catch (JSchException ex) {
			Logger.getLogger(SSHConnection.class.getName()).log(Level.SEVERE,
					null, ex);
			return false;
		}
	}

	public boolean establishTunnel(Tunnel tunnel) {
		if (!this.session.isConnected()) {
			return false;
		}

		if (this.tunnel_is_established(tunnel)) {
			return true;
		}

		int tunnelLocalPort = tunnel.getLocalPort();
		int tunnelRemotePort = tunnel.getRemotePort();
		String tunnelRemoteHost = tunnel.getRemoteServer();

		try {
			this.session.setPortForwardingL(tunnelLocalPort, tunnelRemoteHost,
					tunnelRemotePort);
			this.established_tunnels.add(tunnel);
			return true;
		} catch (JSchException ex) {
			Throwable cause = ex.getCause();
			if (cause != null) {
				JOptionPane.showMessageDialog(null, "Could not open tunnel: "
						+ cause.getMessage());
			} else {
				JOptionPane.showMessageDialog(null, "Could not open tunnel: "
						+ ex.getMessage());
			}
			Logger.getLogger(SSHConnection.class.getName()).log(Level.SEVERE,
					null, ex);
			return false;
		}
	}

	public void close() {
		if (!this.session.isConnected()) {
			return;
		}
		for (Tunnel tunnel : new ArrayList<Tunnel>(this.established_tunnels)) {
			this.destroyTunnel(tunnel);
		}
		this.session.disconnect();
	}

	public Server getServer() {
		return this.server;
	}

	public SSHUserData getData() {
		return this.data;
	}
}
